package com.jacky.iot;

import org.eclipse.californium.cli.decoder.CborDecoder;
import org.eclipse.californium.cli.decoder.JsonDecoder;
import org.eclipse.californium.core.CoapClient;
import org.eclipse.californium.core.CoapResponse;
import org.eclipse.californium.core.Utils;
import org.eclipse.californium.core.coap.MediaTypeRegistry;
import org.eclipse.californium.core.coap.Request;
import org.eclipse.californium.core.coap.Token;
import org.eclipse.californium.core.config.CoapConfig;
import org.eclipse.californium.elements.EndpointContext;
import org.eclipse.californium.elements.config.Configuration;
import org.eclipse.californium.elements.config.UdpConfig;
import org.eclipse.californium.elements.exception.ConnectorException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;

public class DemoClient {

    private static final Logger log = LoggerFactory.getLogger(DemoClient.class);

    private static final File CONFIG_FILE = new File("Californium3.properties");
    private static final String CONFIG_HEADER = "Californium CoAP Properties file for client";
    private static final int DEFAULT_MAX_RESOURCE_SIZE = 2 * 1024 * 1024; // 2 MB
    private static final int DEFAULT_BLOCK_SIZE = 512;

    static {
        CoapConfig.register();
        UdpConfig.register();
    }

    private static Configuration.DefinitionsProvider DEFAULTS = new Configuration.DefinitionsProvider() {

        @Override
        public void applyDefinitions(Configuration config) {
            config.set(CoapConfig.MAX_RESOURCE_BODY_SIZE, DEFAULT_MAX_RESOURCE_SIZE);
            config.set(CoapConfig.MAX_MESSAGE_SIZE, DEFAULT_BLOCK_SIZE);
            config.set(CoapConfig.PREFERRED_BLOCK_SIZE, DEFAULT_BLOCK_SIZE);
        }
    };

    public static void main(String[] args) throws Exception {
        Configuration config = Configuration.createWithFile(CONFIG_FILE, CONFIG_HEADER, DEFAULTS);
        Configuration.setStandard(config);

        CoapClient clientPing = new CoapClient("coap://127.0.0.1:5683");
        if (!clientPing.ping(2000)) {
            log.info("coap://127.0.0.1:5683 does not respond to ping, exiting...");
            System.exit(-1);
        } else {
            log.info("coap://127.0.0.1:5683 respond to ping");
        }
        EndpointContext context = clientPing.getDestinationContext();
        if (context != null) {
            log.info(Utils.prettyPrint(context));
        }

        test(clientPing.getURI(), context);
    }


    public static void test(String uri, EndpointContext context) throws ConnectorException, IOException {
        CoapResponse response;

        CoapClient client = new CoapClient(uri + "/test");
        client.setDestinationContext(context);
        log.info("ep context:{}", Utils.prettyPrint(context));

        context = client.getDestinationContext();
        if (context != null) {
            log.info("destination context:{}", Utils.prettyPrint(context));
        }
        log.info("----- ACK GET START -----");
        response = client.get();
        log.info("[GET] resp type:{},code:{}", response.advanced().getType(), response.getCode());
        log.info("[GET] resp hexString:{}", Utils.toHexString(response.advanced().getBytes()));
        log.info("[GET] resp context:\n{}", response.getResponseText());
        log.info("----- ACK GET END -----\n\n");

        log.info("----- ACK DELETE START -----");
        response = client.delete();
        log.info("[DELETE] resp type:{},code:{}", response.advanced().getType(), response.getCode());
        log.info("[DELETE] resp hexString:{}", Utils.toHexString(response.advanced().getBytes()));
        log.info("[DELETE] resp context:\n{}", response.getResponseText());
        log.info("----- ACK DELETE END -----\n\n");


        log.info("----- ACK PUT START -----");
        response = client.put("", MediaTypeRegistry.TEXT_PLAIN);
        log.info("[PUT] resp type:{},code:{}", response.advanced().getType(), response.getCode());
        log.info("[PUT] resp hexString:{}", Utils.toHexString(response.advanced().getBytes()));
        log.info("[PUT] resp context:\n{}", response.getResponseText());
        log.info("----- ACK PUT END -----\n\n");

        log.info("----- ACK POST START -----");
        response = client.post("empty", MediaTypeRegistry.TEXT_PLAIN);
        log.info("[POST] resp type:{},code:{}", response.advanced().getType(), response.getCode());
        log.info("[POST] resp hexString:{}", Utils.toHexString(response.advanced().getBytes()));
        log.info("[POST] resp context:\n{}", response.getResponseText());
        log.info("----- ACK POST END -----\n\n");


        client.useNONs();
        log.info("--------------- client set to NON ---------------");
        log.info("----- NON GET START -----");
        response = client.get();
        log.info("[NON GET] resp type:{},code:{}", response.advanced().getType(), response.getCode());
        log.info("[NON GET] resp hexString:{}", Utils.toHexString(response.advanced().getBytes()));
        log.info("[NON GET] resp context:\n{}", response.getResponseText());
        log.info("----- NON GET END -----\n\n");

        log.info("----- NON DELETE START -----");
        response = client.delete();
        log.info("[NON DELETE] resp type:{},code:{}", response.advanced().getType(), response.getCode());
        log.info("[NON DELETE] resp hexString:{}", Utils.toHexString(response.advanced().getBytes()));
        log.info("[NON DELETE] resp context:\n{}", response.getResponseText());
        log.info("----- NON DELETE END -----\n\n");


        log.info("----- NON PUT START -----");
        response = client.put("", MediaTypeRegistry.TEXT_PLAIN);
        log.info("[NON PUT] resp type:{},code:{}", response.advanced().getType(), response.getCode());
        log.info("[NON PUT] resp hexString:{}", Utils.toHexString(response.advanced().getBytes()));
        log.info("[NON PUT] resp context:\n{}", response.getResponseText());
        log.info("----- NON PUT END -----\n\n");

        log.info("----- NON POST START -----");
        response = client.post("empty", MediaTypeRegistry.TEXT_PLAIN);
        log.info("[NON POST] resp type:{},code:{}", response.advanced().getType(), response.getCode());
        log.info("[NON POST] resp hexString:{}", Utils.toHexString(response.advanced().getBytes()));
        log.info("[NON POST] resp context:\n{}", response.getResponseText());
        log.info("----- NON POST END -----\n\n");


        log.info("--------------- client set to CON ---------------");
        log.info("----- CON separate GET START -----");
        client.useCONs();
        client.setURI(uri + "/separate");
        response = client.get();
        log.info("[CON separate GET] resp type:{},code:{}", response.advanced().getType(), response.getCode());
        log.info("[CON separate GET] resp hexString:{}", Utils.toHexString(response.advanced().getBytes()));
        log.info("[CON separate GET] resp context:\n{}", response.getResponseText());
        log.info("----- CON separate GET END -----\n\n");

        log.info("----- CON test GET without token START -----");
        client.setURI(uri + "/test");
        Request getReq = Request.newGet();
        getReq.setToken(Token.EMPTY);
        response = client.advanced(getReq);
        log.info("[CON w/o GET] resp type:{},code:{}", response.advanced().getType(), response.getCode());
        log.info("[CON w/o GET] resp hexString:{}", Utils.toHexString(response.advanced().getBytes()));
        log.info("[CON w/o GET] resp context:\n{}", response.getResponseText());
        log.info("----- CON test GET without token END -----\n");

        log.info("----- long path START -----");
        client.setURI(uri + "/seg1");
//        client.setURI(uri + "/seg1/seg2");
//        client.setURI(uri + "/seg1/seg2/seg3");
        response = client.get();
        log.info("[seg GET] resp type:{},code:{}", response.advanced().getType(), response.getCode());
        log.info("[seg GET] resp hexString:{}", Utils.toHexString(response.advanced().getBytes()));
        log.info("[seg GET] resp context:\n{}", response.getResponseText());
        log.info("----- long path END -----\n");

        log.info("----- query START: /query?first=1&second=2 -----");
        client.setURI(uri + "/query?first=1&second=2");
        response = client.get();
        log.info("[query GET] resp type:{},code:{}", response.advanced().getType(), response.getCode());
        log.info("[query GET] resp hexString:{}", Utils.toHexString(response.advanced().getBytes()));
        log.info("[query GET] resp context:\n{}", response.getResponseText());
        log.info("----- query END -----\n");

        log.info("----- separate START: /separate -----");
        client.setURI(uri + "/separate");
        client.setTimeout(10000L); // 设置超时时间
        response = client.get();
        log.info("[separate GET] resp type:{},code:{}", response.advanced().getType(), response.getCode());
        log.info("[separate GET] resp hexString:{}", Utils.toHexString(response.advanced().getBytes()));
        log.info("[separate GET] resp context:\n{}", response.getResponseText());
        log.info("----- separate END -----\n");

        log.info("----- test resource post START: /test -----");
        client.setURI(uri + "/test");
        client.setTimeout(0L);
        client.useCONs();
        response = client.post("测试资源[/test]的POST请求", MediaTypeRegistry.TEXT_PLAIN);
        log.info("[test POST] resp type:{},code:{}", response.advanced().getType(), response.getCode());
        log.info("[test POST] resp hexString:{}", Utils.toHexString(response.advanced().getBytes()));
        log.info("[test POST] resp context:\n{}", response.getResponseText());
        log.info("----- test resource post END -----\n");

        log.info("----- location query START: /location-query -----");
        client.setURI(uri + "/location-query");
        response = client.post("query", MediaTypeRegistry.TEXT_PLAIN);
        log.info("[location-query POST] resp type:{},code:{}", response.advanced().getType(), response.getCode());
        log.info("[location-query POST] resp hexString:{}", Utils.toHexString(response.advanced().getBytes()));
        log.info("[location-query POST] resp context:\n{}", response.getResponseText());
        log.info("----- location-query post END -----\n");

        log.info("----- 多种数据格式 START: /multi-format -----");
        client.setURI(uri + "/multi-format");
        response = client.get(MediaTypeRegistry.TEXT_PLAIN);
        log.info("[multi-format GET] request format type:{}", MediaTypeRegistry.TEXT_PLAIN);
        log.info("[multi-format GET] resp type:{},code:{}", response.advanced().getType(), response.getCode());
        log.info("[multi-format GET] resp context:\n{}", response.getResponseText());

        response = client.get(MediaTypeRegistry.APPLICATION_XML);
        log.info("[multi-format GET] request format type:{}", MediaTypeRegistry.APPLICATION_XML);
        log.info("[multi-format GET] resp type:{},code:{}", response.advanced().getType(), response.getCode());
        log.info("[multi-format GET] resp context:\n{}", response.getResponseText());

        response = client.get(MediaTypeRegistry.APPLICATION_JSON);
        log.info("[multi-format GET] request format type:{}", MediaTypeRegistry.APPLICATION_JSON);
        log.info("[multi-format GET] resp type:{},code:{}", response.advanced().getType(), response.getCode());
        log.info("[multi-format GET] resp decode Json:\n{}", new JsonDecoder().decode(response.getPayload()));

        response = client.get(MediaTypeRegistry.APPLICATION_CBOR);
        log.info("[multi-format GET] request format type:{}", MediaTypeRegistry.APPLICATION_CBOR);
        log.info("[multi-format GET] resp type:{},code:{}", response.advanced().getType(), response.getCode());
        log.info("[multi-format GET] decode cbor:\n{}", new CborDecoder().decode(response.getPayload()));
        log.info("----- 多种数据格式 END -----\n");


    }

}